<template>
  <div 图容器根元素 pos-relative flex-1 flex content-start items-start flex-wrap
    ref="graphRoot"
    @click="clickRoot"
    @mousemove="onMouseMoveRoot"
    @wheel="onWheel"
    class="graph-root color-content-2"
    :style="{
      backgroundImage: `url(${bg})`,
      overflowY: 'hidden',
      overflowX: 'scroll',
    }">

    <CreateNodeMenu ref="createNodeMenu"/>

    <div z-10 图容器 pos-absolute style="width: 5600px; height: 100%;">

      <NodeDisplay v-for="(node, index) in graph.nodes" :node="node" />

      <svg width="5600" :height="graphH" :view-box="`0 0 5600 ${graphH}`">
        <line v-if="oBus.pendingSlotPoint"
          stroke="var(--color-body)" stroke-width="1"
          :x1="startPoint.x" :y1="startPoint.y" :x2="endPoint.x" :y2="endPoint.y"/>
        <line v-for="(line, index) in lines"
          stroke="var(--color-body)" :stroke-width="1"
          :x1="line.p1.x" :y1="line.p1.y" :x2="line.p2.x" :y2="line.p2.y"/>
      </svg>
    </div>
  </div>
</template>

<script setup lang="ts">
import NodeDisplay from './NodeDisplay.vue';
import { oGraph, Graph } from '~/models/graph/graph';
import bg from 'assets/blueprint-bg.svg'
import { MathPoint } from '~/models/Math/MathPoint';
import lodash from 'lodash'
import type { ISlot } from '~/models/graph/slot/instance';
import { MathLine } from '~/models/Math/MathLine';
import { oBus } from '~/models/graph/editorbus';
import CreateNodeMenu from './CreateNodeMenu.vue';

const props = defineProps<{
  graph: Graph
}>()

const graphRoot = ref(null as null | HTMLElement)
const createNodeMenu = ref<InstanceType<typeof CreateNodeMenu> | null>(null)

onMounted(() => {
  oBus.value.rootElement = graphRoot.value!
})

/**
 * 检测元素宽高，修改svg画布大小
 */
const graphW = ref(0)
const graphH = ref(0)
function onResize() {
  // console.log('onresize');
  
  const r = graphRoot.value!.getBoundingClientRect()
  if (r.width && r.height) {
    graphW.value = r.width
    graphH.value = r.height
  }
}
onMounted(() => {
  onResize()
  window.addEventListener('resize', onResize)
})
onUnmounted(() => {
  window.removeEventListener('resize', onResize)
})


function clickRoot(ev: MouseEvent) {
  // console.log('GraphDisplay: clickRoot', ev);
  
  // 菜单
  // 如果是pending状态，就弹出菜单。否则隐藏菜单
  if (oBus.value.pendingSlotPoint) {
    createNodeMenu.value?.pop(ev)
  }

  // 选中节点：取消
  oBus.value.activeNode = undefined
}

/**
 * 
 * 处理连接slot相关的事件
 * 
 */
const startPoint = computed(() => {
  if (!oBus.value.pendingSlotPoint) {
    return new MathPoint()
  }
  else {
    const p0 = oBus.value.pendingSlotPoint
    const r = graphRoot.value!.getBoundingClientRect()
    
    return new MathPoint(p0.x - r.left, p0.y - r.top)
  }
})

const endPoint = ref(new MathPoint())
function onMouseMoveRoot(ev: MouseEvent) {
  if (!createNodeMenu.value?.show) {
    const r = graphRoot.value!.getBoundingClientRect()
    endPoint.value.x = ev.clientX - r.x
    endPoint.value.y = ev.clientY - r.y
  }
}

function keyDownGlobal(ev: KeyboardEvent) {
  // console.log(ev);
  
  // Esc: 取消pending状态
  if (ev.code == 'Escape') {
    oBus.value.pendingSlot = undefined
    oBus.value.pendingSlotPoint = undefined
    createNodeMenu.value?.hide()
  }
  
  // console.log(ev);
  
  // Delete: 删除活动节点
  if (ev.code == 'Delete') {
    oBus.value.deleteActiveNode()
  }
}
onMounted(() => {
  window.addEventListener('keydown', keyDownGlobal)
})
onUnmounted(() => {
  window.removeEventListener('keydown', keyDownGlobal)
})

/**
 * 
 * End
 * 
 */


/**
 * 
 * 处理link相关
 * 
 */

const lines = computed(() => {

  if (!graphRoot.value) {
    return []
  }
  // console.log(oGraph.value);
  
  const allSlots = lodash.flatten(oGraph.value?.nodes.map(x => x.slots))
  
  const slots: ISlot[] = allSlots.filter(x => x.peer)

  const half: ISlot[] = []
  slots.forEach(s => {
    if (half.find(x => x.peer === s)) {
      return
    }
    half.push(s)
  })
  // half.forEach(slot => {
  //   console.log(`p0: ${slot.x}, ${slot.y} p1: ${slot.peer!.x}, ${slot.peer!.y}`);
  // })

  const r = graphRoot.value!.getBoundingClientRect()

  return half.map(s => new MathLine(new MathPoint(s.x - r.x, s.y - r.y), new MathPoint(s.peer!.x - r.x, s.peer!.y - r.y)))
})

/**
 * 
 * End
 * 
 */


/** 实现横向滚动 */
function onWheel(ev: WheelEvent) {
  const delta = ev.deltaX || ev.deltaY
  graphRoot.value!.scrollBy({
    top: 0,
    left: delta,
    // behavior: 'smooth',
  })
  // console.log(ev);
  
  ev.preventDefault()
}
</script>